package com.harboursoftware.xstorage.unit.web

import com.google.common.collect.ArrayListMultimap 
import com.google.common.collect.TreeMultimap 
import org.junit.Test;
import org.junit.After 
import org.junit.Before 
import org.junit.Test 
import org.springframework.mock.web.MockHttpServletRequest 

import com.harboursoftware.xstorage.model.XBucket 
import com.harboursoftware.xstorage.model.XObject 
import com.harboursoftware.xstorage.web.AuthorizationChecker;
import com.harboursoftware.xstorage.web.StorageServlet;

import com.harboursoftware.xstorage.Constants;
import com.harboursoftware.xstorage.XStorageException 

/**
 * Test case from 
 * <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html">Authenticating REST Requests</a> 
 * @author Simon Leung
 * @since 0.1
 */
class AuthorizationCheckerTest {
    StorageServlet servlet
    def secretAccessKey = 'uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o'
    @Before
    void setUp() {
        servlet = new StorageServlet()
        
    }
    
    @After
    void tearDown() {
        servlet = null
    }

    
    @Test
    void test_sign_1() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('get', '/photos/puppy.jpg')
        request.setServerName("johnsmith" + Constants.XS_HOSTNAME_SUFFIX)
        request.addHeader("Host", "johnsmith.s.x-storage.com")
        request.addHeader("Date", "Tue, 27 Mar 2007 19:36:42 +0000")
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'xXjDGYUmKxnwqr5KXNPGldn5LbA='
    }
    
    @Test
    void test_sign_2() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('put', '/photos/puppy.jpg')
        request.setServerName("johnsmith" + Constants.XS_HOSTNAME_SUFFIX)
        request.addHeader("Content-Type", "image/jpeg")
        request.addHeader("Content-Length", "94328")
        request.addHeader("Host", "johnsmith.s.x-storage.com")
        request.addHeader("Date", "Tue, 27 Mar 2007 21:15:45 +0000")
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'hcicpDDvL9SsO6AkvxqmIWkmOuQ='
    }
    
    @Test
    void test_sign_3() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('GET', '/')
        request.setServerName("johnsmith" + Constants.XS_HOSTNAME_SUFFIX)
        request.addHeader("User-Agent", "Mozilla/5.0")
        request.addHeader("Content-Length ", "94328")
        request.addHeader("Host", "johnsmith.s.x-storage.com")
        request.addHeader("Date", "Tue, 27 Mar 2007 19:42:41 +0000")

        request.addParameter("prefix", "photos")
        request.addParameter("max-keys", "50")
        request.addParameter("marker", "puppy")

        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'jsRt/rhG+Vtp88HrYL706QhE4w4='
    }
    
    @Test
    void test_sign_4() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('GET', '/')
        request.setServerName("johnsmith" + Constants.XS_HOSTNAME_SUFFIX)
        request.addHeader("Host", "johnsmith.s.x-storage.com ")
        request.addHeader("Date", " Tue, 27 Mar 2007 19:44:46 +0000 ")
        request.setContent(new byte[0])
        request.addParameter("acl", '')
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'thdUi9VAkzhkniLj96JIrOPGi0g='
    }
    
    @Test
    void test_sign_5() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('delete', '/johnsmith/photos/puppy.jpg')
        request.setServerName(Constants.XS_HOSTNAME)
        request.addHeader("User-Agent", " dotnet")
        request.addHeader("Host", "s.x-storage.com ")
        request.addHeader("Date", "Tue, 27 Mar 2007 21:20:27 +0000");
        request.addHeader("X-AMZ-date", "Tue, 27 Mar 2007 21:20:26 +0000");
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'k3nL7gH3+PadhTEVn5Ip83xlYzk='
    }
    
    @Test
    void test_sign_6() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('PUT', '/db-backup.dat.gz')
        request.setServerName('static.johnsmith.net')
        request.addHeader("User-Agent", " curl/7.15.5")
        request.addHeader("Host", "static.johnsmith.net")
        request.addHeader("Date", "Tue, 27 Mar 2007 21:06:08 +0000");
        request.addHeader("x-amz-acl", "public-read");
        request.addHeader("content-type", "application/x-download");
        request.addHeader("Content-MD5", "4gJE4saaMU4BqNR0kLY+lw==");
        request.addHeader("X-Amz-Meta-ReviewedBy", "joe@johnsmith.net");
        request.addHeader("X-Amz-Meta-ReviewedBy", "jane@johnsmith.net");
        request.addHeader("X-Amz-Meta-FileChecksum", "0x02661779");
        request.addHeader("X-Amz-Meta-ChecksumAlgorithm", "crc32");
        request.addHeader("Content-Disposition", "attachment; filename=database.dat");
        request.addHeader("Content-Encoding", "gzip");
        request.addHeader("Content-Length", "5913339");
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        println stringToSign
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'C0FlOtU8Ylb9KDTpZqYkZPX91iI='
    }
    
    @Test
    void test_sign_7() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('get', '/')
        request.setServerName(Constants.XS_HOSTNAME)
        request.addHeader("Host", Constants.XS_HOSTNAME)
        request.addHeader("Date", " Wed, 28 Mar 2007 01:29:59 +0000");

        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'Db+gepJSUbZKwpx1FR0DLtEYoZA='
    }
    
    @Test
    void test_sign_8() { 
        
        MockHttpServletRequest request = new MockHttpServletRequest('get', '/dictionary/fran%C3%A7ais/pr%c3%a9f%c3%a8re')
        request.setServerName(Constants.XS_HOSTNAME)
        request.addHeader("Host", Constants.XS_HOSTNAME)
        request.addHeader("Date", " Wed, 28 Mar 2007 01:49:49 +0000");
        
        
        def bucket = servlet.createBucket(request)
        def object = servlet.createObject(request)
        def headers = servlet.getHeaders(request)
        def params = servlet.getParameters(request)
        def stringToSign = AuthorizationChecker.createStringToSign(request.getMethod(), bucket, object, headers, params)
        def signature = AuthorizationChecker.sign(secretAccessKey, stringToSign)
        assert signature == 'dxhSBHoI6eVSPcXJqEghlUzZMnY='
    }
    
    @Test
    void test_check_1() {
        def method = 'GET'
        def bucket = new XBucket(name : 'johnsmith')
        def object = new XObject(key : '/photos/puppy.jpg')
        def headers = ArrayListMultimap.create()
        headers.put 'date', 'Tue, 27 Mar 2007 19:36:42 +0000'
        headers.put 'authorization', 'AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA='
        def parameters = [:]
        def user = AuthorizationChecker.check(method, bucket, object, headers, parameters);
        assert user != null
    }
    
    @Test(expected = XStorageException.class)
    void test_check_1_signs_not_match() {
        def method = 'GET'
        def bucket = new XBucket(name : 'johnsmith')
        def object = new XObject(key : '/photos/puppy.jpg')
        def headers = ArrayListMultimap.create()
        headers.put 'date', 'Tue, 27 Mar 2007 19:36:42 +0000'
        headers.put 'authorization', 'AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5Lbbb'
        def parameters = [:]
        def user = AuthorizationChecker.check(method, bucket, object, headers, parameters);
    }
    
   
    
    @Test
    void test_check_when_authorizaton_header_is_invalid_1() {
        def method = 'GET'
        def bucket = new XBucket(name : 'johnsmith')
        def object = new XObject(key : '/photos/puppy.jpg')
        def headers = ArrayListMultimap.create()
        headers.put 'date', 'Tue, 27 Mar 2007 19:36:42 +0000'
        //remove 'AWS'
        headers.put 'authorization', ' 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5Lbbb'
        def parameters = [:]
        def errorCode
        def errorMessage
        try {
            def user = AuthorizationChecker.check(method, bucket, object, headers, parameters)
        } catch (e) {
            errorCode = e.errorResult.code
            errorMessage = e.errorResult.message
        }
        assert errorCode == 'InvalidArgument'
        assert errorMessage == /Authorization header is invalid -- one and only one ' ' (space) required/
    }
    
    @Test
    void test_check_when_authorizaton_header_is_invalid_2() {
        def method = 'GET'
        def bucket = new XBucket(name : 'johnsmith')
        def object = new XObject(key : '/photos/puppy.jpg')
        def headers = ArrayListMultimap.create()
        headers.put 'date', 'Tue, 27 Mar 2007 19:36:42 +0000'
       //remove 'AW'
        headers.put 'authorization', 'S 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5Lbbb'
        def parameters = [:]
        def errorCode
        def errorMessage
        try {
            def user = AuthorizationChecker.check(method, bucket, object, headers, parameters)
        } catch (e) {
            errorCode = e.errorResult.code
            errorMessage = e.errorResult.message
        }
        assert errorCode == 'InvalidArgument'
        assert errorMessage == 'Unsupported Authorization Type'
    }
    
    @Test
    void test_check_when_authorizaton_header_is_invalid_3() {
        def method = 'GET'
        def bucket = new XBucket(name : 'johnsmith')
        def object = new XObject(key : '/photos/puppy.jpg')
        def headers = ArrayListMultimap.create()
        headers.put 'date', 'Tue, 27 Mar 2007 19:36:42 +0000'
        //remove ':'
        headers.put 'authorization', 'AWS 0PN5J17HBGZHT7JJ3X82xXjDGYUmKxnwqr5KXNPGldn5Lbbb'
        def parameters = [:]
        def errorCode
        def errorMessage
        try {
            def user = AuthorizationChecker.check(method, bucket, object, headers, parameters)
        } catch (e) {
            errorCode = e.errorResult.code
            errorMessage = e.errorResult.message
        }
        assert errorCode == 'InvalidArgument'
        assert errorMessage == 'AWS authorization header is invalid.  Expected AwsAccessKeyId:signature'
    }
}
